

#include <BImage>
#include <BFile>
#include "ReadWrite_jpg.h"

#include <stdio.h>
#include <jpeglib.h>

ReadWrite_jpg::ReadWrite_jpg()
{
	_author = "zym";
	_version = "1.0";
	_description = "This is BWE Plugin for reading *.jpg image file, writen width libjpeg, thank a lot !";
}
ReadWrite_jpg::~ReadWrite_jpg()
{

}

const BString& ReadWrite_jpg::author() const
{
	return _author;
}
const BString& ReadWrite_jpg::version() const
{
	return _version;
}
const BString& ReadWrite_jpg::description() const
{
	return _description;
}
const BString& ReadWrite_jpg::log() const
{
	return _log;
}

BObject* ReadWrite_jpg::readObject(const BString& fileName)
{
	FILE* file = ::fopen(fileName.cstr(), "rb");
	if(!file)
	{
	    return 0;
	}

	jpeg_decompress_struct cinfo;
	jpeg_error_mgr err;

	cinfo.err = jpeg_std_error(&err);
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, file);

	jpeg_read_header(&cinfo, true);
	jpeg_start_decompress(&cinfo);

	int components = cinfo.out_color_components;
	int width = cinfo.image_width;
	int height = cinfo.image_height;
	int rowbytes = width * components;

	int size = width * height * components;
	BHolder<BByteArray> pixels = new BByteArray(rowbytes * height);
	BByte* data = pixels->data();

	BArray<BByte*> row_pointers(height);
	for(int i = 0; i < height; i++ )
		row_pointers[i] = &data[i * rowbytes];

	while( cinfo.output_scanline < cinfo.output_height )
	{
		jpeg_read_scanlines( &cinfo, &row_pointers[cinfo.output_scanline], cinfo.output_height - cinfo.output_scanline );
	}

	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

	BImage* image = new BImage();
	if(cinfo.out_color_components == 4)
		image->setFormat(Format_RGBA);
	else
		image->setFormat(Format_RGB);
	image->setWidth(width);
	image->setHeight(height);
	image->setPixels(pixels.ptr());

	fclose(file);
	return image;
}

bool ReadWrite_jpg::writeObject(const BObject* object, const BString& fileName)
{
	FILE * file = fopen(fileName.cstr(), "wb");
	if(file == NULL)
	{
	    return false;
	}

	const BImage* image = dynamic_cast<const BImage*>(object);
	if (image == 0)
		return false;

	jpeg_compress_struct cinfo;
	jpeg_error_mgr jerr;
	cinfo.err = jpeg_std_error(&jerr);

	jpeg_create_compress(&cinfo);
	if (image->format() == Format_RGB || image->format() == Format_BGR)
	{
		cinfo.in_color_space = JCS_RGB;
		cinfo.input_components = 3;
	}
	if (image->format() == Format_RGBA || image->format() == Format_BGRA)
	{
		cinfo.in_color_space = JCS_CMYK;
		cinfo.input_components = 4;
	}
	jpeg_set_defaults(&cinfo);
	jpeg_stdio_dest(&cinfo, file);
	cinfo.image_width = image->width();
	cinfo.image_height = image->height();

	int width = cinfo.image_width;
	int height = cinfo.image_height;
	int components = cinfo.input_components;
	BByte* data = (BByte*)image->pixels()->data();

	jpeg_start_compress(&cinfo, true);
	while(cinfo.next_scanline < cinfo.image_height)
	{
		BByte* row_pointer = data + width * components * cinfo.next_scanline;
		jpeg_write_scanlines(&cinfo, &row_pointer, 1);
	}
	jpeg_finish_compress(&cinfo);
	jpeg_destroy_compress(&cinfo);

	fclose(file);
	return true;
}
